package org.vacoor.nothing.ui.util;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.IOException;
import java.util.Iterator;

/**
 * 图像操作类
 * <p/>
 * 获取图像的类型,剪裁图像,缩放图像等操作
 *
 * @author vacoor
 * @version 1.0
 * @see javax.imageio.ImageIO
 */
public class ImageUtil {
    /**
     * 获取指定图像的类型
     * <p/>
     * 通过ImageIO.createImageInputStream(Object)来读取
     *
     * @param input 用作输入源的 Object，比如 File、可读取的 RandomAccessFile 或 InputStream
     * @return 图像的类型
     * @see javax.imageio.ImageIO#createImageInputStream(Object)
     */
    public static String getImageFormat(Object input) {
        String format = "unknown";
        try {
            ImageInputStream iis = ImageIO.createImageInputStream(input);
            Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
            iis.close();
            if (iter.hasNext()) {
                format = ((ImageReader) iter.next()).getFormatName();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return format;
    }

    /**
     * 将Image对象转换为指定透明度的BufferedImage
     *
     * @param img   需要转换的Image对象
     * @param alpha 转换后的透明度,alpha 取值为 0.0f ~ 1.0f
     * @return 转换后的BufferedImage对象
     */
    public static BufferedImage getBufferedImage(Image img, float alpha) {
        BufferedImage bufferedImage;
        if (((img instanceof BufferedImage)) && ((alpha < 0.0D) || (alpha >= 1.0D))) {
            bufferedImage = (BufferedImage) img;
        } else {
            int w = img.getWidth(null);
            int h = img.getHeight(null);
            bufferedImage = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
            Graphics2D g = bufferedImage.createGraphics();
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            if ((alpha >= 0.0D) && (alpha < 1.0D)) {
                g.setComposite(AlphaComposite.SrcOver.derive(alpha));
            }
            g.drawImage(img, 0, 0, null);
            g.dispose();
        }
        return bufferedImage;
    }

    /**
     * 将Image对象转换为BufferedImage对象
     * <p/>
     * 等同:
     * <pre>
     * 	    </code>
     * 		getBufferedImage(img,1f);
     * 		</code>
     * </pre>
     *
     * @see org.vacoor.nothing.nothing.util.ImageUtil#getBufferedImage(java.awt.Image, float)
     */
    public static BufferedImage getBufferedImage(Image img) {
        return getBufferedImage(img, 1f);
    }

    /**
     * 获取图像的指定区域
     *
     * @param originalImg 要剪裁的图片
     * @param rect        要剪裁的区域
     * @return 剪裁后的图片
     */
    public static BufferedImage getCutImage(BufferedImage originalImg, Rectangle rect) {
        BufferedImage newImg = new BufferedImage(rect.width, rect.height, BufferedImage.TRANSLUCENT);
        Graphics2D g = newImg.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.drawImage(originalImg, 0, 0, rect.width, rect.height, rect.x, rect.y, rect.width + rect.x, rect.height + rect.y, null);
        g.dispose();
        return newImg;
    }

    /**
     * 缩放图像大小
     *
     * @param originalImg 需要缩放的图像
     * @param width       缩放后的新宽度
     * @param height      缩放后的新高度
     * @return 缩放后的图像
     */
    public static BufferedImage getResizeImage(BufferedImage originalImg, int width, int height) {
        Image img = originalImg.getScaledInstance(width, height, Image.SCALE_FAST);
        return getBufferedImage(img);
    }

	/*
    public static BufferedImage getResizeImage(BufferedImage originalImg,int width,int height) {
		int w = originalImg.getWidth();
		int h = originalImg.getHeight();
		
		BufferedImage newImg = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
		//这里除以1.0转换为浮点数运算,防止结果为0
		double wBo = width / 1.0 / w;
		double hBo = height / 1.0 / h;
		AffineTransform transform = new AffineTransform();
		System.out.println(wBo +"," +hBo);
		transform.setToScale(wBo,hBo);
		// 根据原始图片生成处理后的图片。
		AffineTransformOp ato = new AffineTransformOp(transform, null);
		ato.org.vacoor.nothing.web.filter(originalImg, newImg);
		return newImg;
	}
	*/

    /**
     * 按比例缩放图像
     *
     * @param originalImg 需要缩放的图像
     * @param widthBo     宽度的缩放比例,浮点数表示
     * @param heightBo    高度的缩放比例,浮点数表示
     * @return 缩放后的图像
     */
    public static BufferedImage getResizeImage(BufferedImage originalImg, double widthBo, double heightBo) {
        return getResizeImage(originalImg,
                (int) (originalImg.getWidth() * widthBo),
                (int) (originalImg.getHeight() * heightBo));
    }


    /**
     * 将图像按照指定的角度进行旋转
     *
     * @param originalImg 需要旋转的图像
     * @param angle       旋转的角度
     * @return 旋转后的图像
     */
    public static BufferedImage getRotateImage(BufferedImage originalImg, int angle) {
        //转换为弧度
        double radians = Math.toRadians(angle % 360d);
        int oWidth = originalImg.getWidth();
        int oHeight = originalImg.getHeight();
        //计算新宽高
        int w = (int) (Math.abs(Math.cos(radians) * oWidth) + Math.abs(Math.sin(radians) * oHeight));
        int h = (int) (Math.abs(Math.sin(radians) * oWidth) + Math.abs(Math.cos(radians) * oHeight));
        //中心坐标
        int cX = w / 2;
        int cY = h / 2;
        //创建一个支持指定透明度的BufferedImage
        BufferedImage newImg = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
        Graphics2D g = newImg.createGraphics();
        //算法设置为抗锯齿，抗锯齿提示值——使用抗锯齿模式完成呈现
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.rotate(radians, cX, cY);
        g.drawImage(originalImg, (w - oWidth) / 2, (h - oHeight) / 2, null);
        //将当前的 Graphics2D Transform 与平移cX,cY后的旋转
        g.rotate(-radians, cX, cY);
        g.dispose();
        return newImg;
    }


    /**
     * 将图像二值化
     *
     * @param originalImg 要处理的图像
     * @return 二值化之后的图像
     */
    public static BufferedImage getBinaryImage(BufferedImage originalImg) {
        int width = originalImg.getWidth();
        int height = originalImg.getHeight();

        BufferedImage newImg = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                int rgb = originalImg.getRGB(i, j);
                newImg.setRGB(i, j, rgb);
            }
        }
        return newImg;
    }

    /**
     * 将图像灰度化
     *
     * @param originalImg 需要进行灰度处理的图像
     * @return 灰度处理后的图像
     * @deprecated
     */
    public static BufferedImage getGrayImage2(BufferedImage originalImg) {
        int width = originalImg.getWidth();
        int height = originalImg.getHeight();

        BufferedImage newImg = new BufferedImage(width, height,
                BufferedImage.TYPE_BYTE_GRAY);
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                int rgb = originalImg.getRGB(i, j);
                newImg.setRGB(i, j, rgb);
            }
        }
        return newImg;
    }

    /**
     * 将图像灰度化
     *
     * @param originalImg 需要进行灰度处理的图像
     * @return 灰度处理后的图像
     */
    public static BufferedImage getGrayImage(BufferedImage originalImg) {
        int imageWidth = originalImg.getWidth();
        int imageHeight = originalImg.getHeight();

        BufferedImage newImg = new BufferedImage(imageWidth, imageHeight,
                BufferedImage.TYPE_3BYTE_BGR);

        //创建一个转换操作类,该类使用灰色颜色空间
        ColorConvertOp cco = new ColorConvertOp(
                ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        cco.filter(originalImg, newImg);
        return newImg;
    }

    /**
     * 图像锐化
     *
     * @param originalImg 要锐化处理的图像
     * @return 锐化处理后的图像
     */
    public static BufferedImage getSharperImage(BufferedImage originalImg) {
        int imageWidth = originalImg.getWidth();
        int imageHeight = originalImg.getHeight();

        BufferedImage newImg = new BufferedImage(imageWidth, imageHeight,
                BufferedImage.TYPE_3BYTE_BGR);
        float[] data = {
                -1.0f, -1.0f, -1.0f,
                -1.0f, 10.0f, -1.0f,
                -1.0f, -1.0f, -1.0f
        };

        Kernel kernel = new Kernel(3, 3, data);
        ConvolveOp co = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        co.filter(originalImg, newImg);
        return newImg;
    }

    /**
     * 图像钝化
     *
     * @param originalImg 要钝化的图像
     * @return 钝化处理后的图像
     */
    public static BufferedImage getDlurImage(BufferedImage originalImg) {
        int imageWidth = originalImg.getWidth();
        int imageHeight = originalImg.getHeight();

        BufferedImage newImg = new BufferedImage(imageWidth, imageHeight,
                BufferedImage.TYPE_3BYTE_BGR);

        float[] data = {0.0625f, 0.125f, 0.0625f, 0.125f, 0.125f, 0.125f,
                0.0625f, 0.125f, 0.0625f};

        Kernel kernel = new Kernel(3, 3, data);
        ConvolveOp co = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
        co.filter(originalImg, newImg);
        return newImg;
    }

    /**
     * 获取字符串在指定字体中尺寸大小
     *
     * @param font   字符串所使用的字体
     * @param string 字符串对象
     * @return 字符串在指定字体中的尺寸
     */
    public static Dimension getStringDimension(Font font, String string) {
        sun.font.FontDesignMetrics fdm = sun.font.FontDesignMetrics.getMetrics(font);
        return new Dimension(fdm.stringWidth(string), fdm.getHeight());
    }

    /**
     * 获取特定字体字符的尺寸
     *
     * @param font
     * @param c
     * @return 该字符在指定字符中的尺寸
     */
    public static Dimension getCharDimension(Font font, char c) {
        sun.font.FontDesignMetrics fm = sun.font.FontDesignMetrics.getMetrics(font);
        return new Dimension(fm.charWidth(c), fm.getHeight());
    }
	
	/*
	public static void main(String[] args) throws IOException {
		BufferedImage pic = ImageIO.testRead(ImageUtil.class.getClassLoader()
				.getResourceAsStream("img.jpeg"));
		System.out.println(getImageFormat(ImageUtil.class.getClassLoader()
				.getResourceAsStream("a.png")));
		BufferedImage bin = getBinaryImage(pic);
		BufferedImage gray1 = getGrayImage(pic);
		BufferedImage gray2 = getGrayImage2(pic);
		BufferedImage sharp = getSharperImage(pic);
		BufferedImage dlur = getDlurImage(pic);
		BufferedImage rotate = getRotateImage(pic, 45);
		BufferedImage resize = getResizeImage(pic, 1000, 200);
		BufferedImage cut = getCutImage(pic, new Rectangle(10,10,50,50));
		
		ImageIO.testWrite(bin, "png", new File("_bin.png"));
		ImageIO.testWrite(gray1, "png", new File("_gray1.png"));
		ImageIO.testWrite(gray2, "png", new File("_gray2.png"));
		ImageIO.testWrite(sharp, "png", new File("_sharp.png"));
		ImageIO.testWrite(dlur, "png", new File("_dlur.png"));
		ImageIO.testWrite(rotate, "png", new File("_rotate.png"));
		ImageIO.testWrite(resize, "png", new File("_resize.png"));
		ImageIO.testWrite(cut, "png", new File("_cut.png"));
	}
	*/
}
